package controllers

import auth.AuthActionWrapper
import auth.AuthTool._
import config.JwtConfig
import dao._
import play.api.mvc.{AbstractController, ControllerComponents}
import play.api.routing.JavaScriptReverseRouter
import tool.Tool

import javax.inject.Inject
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
import implicits.Implicits._
import shared.pojo.Pojo._
import ujson.play.PlayJson
import upickle.default._
import utils.JwtUtils

import java.time.Clock
import com.softwaremill.quicklens._
import org.mindrot.jbcrypt.BCrypt

/**
 * Created by Administrator on 2019/8/7
 */
class AppController @Inject()(cc: ControllerComponents, jwtConfig: JwtConfig)(
  implicit val accountDao: AccountDao,
  implicit val userDao: UserDao,
  implicit val memberDao: MemberDao,
  implicit val companyMemberDao: CompanyMemberDao,
  implicit val specialMemberDao: SpecialMemberDao,
  implicit val wechatMemberDao: WechatMemberDao,
  implicit val authAction: AuthActionWrapper,
) extends
  AbstractController(cc) {

  private implicit val clock: Clock = Clock.systemUTC

  def login = Action.async { implicit request =>
    val data = PlayJson.transform(request.body.asJson.get, reader[Login.Request])
    val rolesF = Future.sequence(
      List(
        Tool.memberSelectRnRole(data.account, data.password),
        Tool.speicalMemberSelectRnRole(data.account, data.password),
        Tool.companyMemberSelectRnRole(data.account, data.password),
        Tool.wechatMemberSelectRnRole(data.account, data.password),
        Tool.adminSelectRnRole(data.account, data.password),
      )
    )
    rolesF.map { roleOps =>
      val roleOpOp = roleOps.find(_.isDefined)
      val response = roleOpOp match {
        case Some(roleOp) =>
          Login.Response(valid = true, role = roleOp.get.entryName)
        case None =>
          Login.Response(valid = false)
      }
      if (response.valid) {
        val token = JwtUtils.createToken(jwtConfig, UserInfo(account = data.account, role = response.role))
        val newResponse = response.modify(_.token).setTo(token)
        Ok(writeJs(newResponse))
      } else {
        Ok(writeJs(response))
      }

    }
  }

  def memberLogin = Action.async { implicit request =>
    val data = PlayJson.transform(request.body.asJson.get, reader[Login.Request])
    val rolesF = Future.sequence(
      List(
        Tool.memberSelectRnRole(data.account, data.password),
      )
    )
    rolesF.map { roleOps =>
      val response = {
        val roleOpOp = roleOps.find(_.isDefined)
        roleOpOp match {
          case Some(roleOp) =>
            Login.Response(valid = true, role = roleOp.get.entryName)
          case None =>
            Login.Response(valid = false)
        }
      }
      if (response.valid) {
        val token = JwtUtils.createToken(jwtConfig, UserInfo(account = data.account, role = response.role))
        val newResponse = response.modify(_.token).setTo(token)
        Ok(writeJs(newResponse))
      } else {
        Ok(writeJs(response))
      }

    }
  }

  def changePassword = Action.async { implicit request =>
    val data = Tool.transformRq.transform(reader[ChangePassword.Request])
    Tool.updatePassword(data).map { b =>
      val response = if (b) {
        ValidData(valid = true)
      } else {
        ValidData(valid = false)
      }
      Ok(writeJs(response))
    }
  }

  def accountCheck = Action.async { implicit request =>
    val data = Tool.transformRq.transform(reader[AccountData])
    val bsF = Future.sequence(
      List(
        memberDao.accountExist(data.account),
        companyMemberDao.accountExist(data.account),
        specialMemberDao.accountExist(data.account),
      )
    )
    bsF.zip(accountDao.selectById1).map { case (bs, admin) =>
      val response = if (bs.exists(x => x)) {
        ValidData(valid = false)
      } else {
        val valid = if (data.account == admin.account) false else true
        ValidData(valid = valid)
      }
      Ok(writeJs(response))
    }
  }

}
